package com.qf.listener;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.config.DelayedConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheService;
import com.qf.model.StandardReport;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.Map;

/**
 * 将短信是否发送成功与否消息，推送给客户服务器
 * @author lenovo
 * @version V1.0
 * @Date 2021/11/24 19:47
 */
@Component
@Slf4j
public class PushReportListener {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private CacheService cacheService;

    @Autowired
    private ObjectMapper objectMapper;

    private final String[] TTL = {"0","5000","30000","600000","1800000","3600000"};

    /**
     * 监听推送消息report队列，将消息发送给客户端项目
     * @param message
     * @param channel
     * @param report
     */
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void messageHandler(Message message, Channel channel, StandardReport report)throws Exception{
        //1.接受report对象，根据clientid到redis中获取client对象
        Map<String,String> client = cacheService.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + report.getClientID());
        if (client == null){
            log.info("【接口模块 - 推送业务】获取的client对象为空，report={}",report);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        //2.获取client对象中客户项目的回调地址
        String receiveUrl = client.get("receivestatusurl");
        String status = client.get("isreturnstatus");
        //3.判断用户是否需要推送
        if ("0".equals(status)){
            //客户不需要推送
            log.info("【接口模块 - 推送业务】客户不需要推送，report={}",report);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        //4.如果用于需要推送，那么封装http请求，将report推送给客户地址
        String result = sendReport(receiveUrl, report);
        if ("success".equalsIgnoreCase(result)){
            //发送完成
            log.info("【接口模块 - 推送业务】report推送成功!!！");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }else {
            //将消息发送到延时队列中，发送次数+1
            //report.setSendCount(report.getSendCount() + 1);
            sendDelayedQueue(report);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }


    }

    /**
     * 监听延时消息队列
     * 获取需要再次发送的report的短信推送对象
     */
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void delayedListener(Message message, Channel channel, StandardReport report)throws Exception{
        //1.接受report对象，根据clientid到redis中获取client对象
        Map<String,String> client = cacheService.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + report.getClientID());
        if (client == null){
            log.info("【接口模块 - 推送业务】获取的client对象为空，report={}",report);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        //2.发送次数(第一次时次数已经为1，执行完这句代码次数为2)
        report.setSendCount(report.getSendCount() + 1);

        //3.发送
        String receiveUrl = client.get("receivestatusurl");
        String status = client.get("isreturnstatus");
        if ("0".equals(status)){
            //客户不需要推送
            log.info("【接口模块 - 延时队列推送业务】客户不需要推送，report={}",report);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        //4.接收返回的状态，如果为success发送停止
        String result = sendReport(receiveUrl, report);
        if ("success".equalsIgnoreCase(result)){
            //发送完成
            log.info("【接口模块 - 延时队列推送业务】report推送成功!!！");
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }else {
            //5.如果返回状态为空，判断发送次数如果大于5次，停止发送
            sendDelayedQueue(report);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

    }

    /**
     * 负责推送的方法
     * @return
     */
    private String sendReport(String url,StandardReport report) throws Exception{
        //1.封装请求头对象
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        String reportJson = objectMapper.writeValueAsString(report);
        //2.封装请求体对象
        HttpEntity<String> entity = new HttpEntity(reportJson,headers);

        //3.发送，并返回客户端接收状态
        String res = restTemplate.postForObject(url, entity, String.class);
        return res;
    }

    /**
     * 发送推送对象到延时队列中
     * @param report
     */
    private void sendDelayedQueue(StandardReport report){
        if (report.getSendCount() > 5){
            log.info("【接口模块 - 延时队列推送业务】report推送次数过多，停止发送！");
            return;
        }
        //如果小于5次，将消息设置延迟时间发送再次到延时队列中，
        rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE,"report",report,new MessagePostProcessor(){
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setExpiration(TTL[report.getSendCount()]);
                return message;
            }
        });

    }

}
